package com.cgs.query.client.remote

import com.cgs.query.client.connection.ClientPoolConnectionFactory
import com.cgs.query.domain.MappedStatement
import com.cgs.query.exception.QueryException
import com.cgs.query.executor.Executor
import com.cgs.query.service.IQueryService
import com.cgs.query.service.QuerySourceMap
import mu.KotlinLogging

private val logger = KotlinLogging.logger { }

/**
 * 从服务端拿到执行对象,在本地进行执行
 */
class ClientQueryService(
        private val remotingQueryService: IQueryService,
        private val connectionFactory: ClientPoolConnectionFactory,
        private val executor: Executor,
        projectNames: Array<String>
) : IQueryService {

    init {
        if (projectNames.isNotEmpty()) {
            findSourceByProjectNames(projectNames.toList()).map.forEach {
                val querySource = it.value ?: throw QueryException("项目[${it.key}]找不到数据源")
                connectionFactory.registryDataSource(querySource)
                logger.debug { "注册本地项目数据源：${it.key} -> ${querySource.name}" }
            }
        }
    }

    override fun execute(projectName: String, name: String, param: Map<String, Any?>?, timeout: Int?): Any? {
        val defineSource = remotingQueryService.findDefineSourceByWholeNameAndProjectName(name, projectName)
        defineSource.notNull()
        connectionFactory.changedAndRegistry(defineSource.querySource)
        return try {
            executor.execute(MappedStatement(projectName, name, defineSource.querySource!!, defineSource.executionObj!!), param, timeout)
        } catch (e: QueryException) {
            logger.error { "本地执行出错：${e.message} ,尝试远程执行" }
            remotingQueryService.execute(projectName, name, param, timeout)
        }
    }

    override fun findDefineSourceByWholeNameAndProjectName(name: String, projectName: String) =
            remotingQueryService.findDefineSourceByWholeNameAndProjectName(name, projectName)

    override fun findSourceByProjectNames(names: List<String>): QuerySourceMap =
            remotingQueryService.findSourceByProjectNames(names)
}

